import sys
import os
import pygame
import random


def resource_path(relative_path, resource_folder='res'):
    """ 获取资源的绝对路径，适用于开发和打包后的环境 """
    if getattr(sys, 'frozen', False):
        base_path = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__)))
    else:
        base_path = os.path.dirname(__file__)

    # 如果路径中包含"麻将图片"或"密码学者"，则不使用resource_folder
    if "麻将图片" in relative_path or "密码学者" in relative_path:
        file_path = os.path.abspath(os.path.join(base_path, relative_path))
    else:
        file_path = os.path.abspath(os.path.join(base_path, resource_folder, relative_path))

    if not os.path.exists(file_path):
        print(f"Warning: Resource file '{relative_path}' not found at '{file_path}'")
        return None
    return file_path


def load_and_scale_image(image_path, target_size=(72, 78)):  # 增加牌的尺寸 (从50x54增加到72x78)
    """加载并缩放图片到指定大小，使用高质量缩放算法"""
    try:
        if image_path is None:
            raise FileNotFoundError("Image path is None")
        image = pygame.image.load(image_path).convert_alpha()  # 添加 convert_alpha() 以获得更好的性能和透明度支持
        # 使用 smoothscale 获得更好的图像质量
        return pygame.transform.smoothscale(image, target_size)
    except Exception as e:
        print(f"Error loading image {image_path}: {e}")
        # 创建一个默认的空白图片
        surface = pygame.Surface(target_size)
        surface.fill((200, 200, 200))  # 灰色背景
        return surface


# 定义"牌"父类
class Tile:
    def __init__(self):
        self.kind = 'default'  # 牌的种类：'S'（对称加密）、'A'（非对称加密）、'H'（哈希）、'T'（术语）、'Q'（量子）
        self.text = ''  # 牌的中文描述
        self.n = 0  # 牌的数字或字牌的标识（1~9为数字牌，1~8为术语牌）
        self.security_level = 0  # 安全等级（1-9）
        self.year_invented = 0  # 发明年份
        self.key_length = ''  # 密钥长度
        self.application = ''  # 主要应用场景
        self.is_num = False  # 是否为算法牌
        self.is_term = False  # 是否为术语牌
        self.is_quantum = False  # 是否为量子牌
        self.is_post_quantum = False  # 是否为后量子算法
        self.image = None  # 牌的图像
        self.rect = None  # 牌的矩形区域

    def __str__(self):
        return f"{self.n}{self.kind}"

    def __repr__(self):
        return self.text

    def __eq__(self, other):
        if isinstance(other, Tile):
            return self.kind == other.kind and self.n == other.n

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.kind, self.n))

    def __len__(self):
        return 1

    def __lt__(self, other):
        return self.n < other.n

    def __gt__(self, other):
        return self.n > other.n

    def __le__(self, other):
        return self.n <= other.n

    def __ge__(self, other):
        return self.n >= other.n

    def get_detailed_description(self):
        """获取算法的详细密码学描述"""
        return f"{self.text} - 基础密码学算法"


# 定义"对称加密"牌子类 (替代原来的万牌)
class S(Tile):
    def __init__(self, n):
        super().__init__()
        self.kind = 'S'  # Symmetric encryption
        self.n = n
        
        # 对称加密算法映射
        symmetric_algos = {
            1: ("凯撒密码", 1900, "移位", "古典密码"),
            2: ("DES", 1977, "56位", "银行系统"),
            3: ("IDEA", 1991, "128位", "PGP加密"),
            4: ("AES", 2001, "128-256位", "标准加密"),
            5: ("SM4", 2016, "128位", "国产标准"),
            6: ("SM7", 2021, "128位", "国产流密码"),
            7: ("ChaCha20", 2013, "256位", "现代应用"),
            8: ("Blowfish", 1993, "可变", "文件加密"),
            9: ("ZUC", 2011, "128位", "5G通信")
        }
        
        if 1 <= n <= 9:
            algo_info = symmetric_algos[n]
            self.text = algo_info[0]
            self.year_invented = algo_info[1]
            self.key_length = algo_info[2]
            self.application = algo_info[3]
            self.security_level = n
            
            # 加载新的对称加密算法图片
            try:
                image_name = {
                    1: "凯撒.png",
                    2: "DES.png",
                    3: "IDEA.png",
                    4: "AES.png",
                    5: "SM4.png",
                    6: "SM7.png",
                    7: "ChaCha20.png",
                    8: "Blowfish.png",
                    9: "ZUC.png"
                }[n]
                image_file = resource_path(os.path.join("麻将图片", "对称", image_name))
                self.image = load_and_scale_image(image_file)
                self.rect = self.image.get_rect()
            except Exception as e:
                print(f"Error loading symmetric algorithm image for {n}: {e}")
                # 创建一个默认的空白图片
                self.image = pygame.Surface((50, 54))
                self.image.fill((200, 200, 200))  # 灰色背景
                self.rect = self.image.get_rect()
        else:
            # 创建默认图片
            self.image = pygame.Surface((50, 54))
            self.image.fill((200, 200, 200))
            self.rect = self.image.get_rect()
            
        self.is_num = True
        if n >= 8:  # 8-9级为后量子算法
            self.is_post_quantum = True

    def get_detailed_description(self):
        """获取对称加密算法的详细描述"""
        descriptions = {
            1: "凯撒密码 - 最古老的替换密码之一，通过字母表中的固定位移进行加密。虽然简单易懂，但极易被频率分析破解。",
            2: "DES (数据加密标准) - 1977年美国联邦标准，使用56位密钥。采用Feistel网络结构，经过16轮加密。现已被认为不安全。",
            3: "IDEA (国际数据加密算法) - 瑞士开发的分组密码，128位密钥，64位分组。曾用于PGP软件，设计巧妙但专利限制其应用。",
            4: "AES (高级加密标准) - 2001年标准，支持128、192、256位密钥。采用替换-置换网络，广泛应用于各种安全协议。",
            5: "SM4 - 中国国家密码管理局发布的分组密码标准。128位密钥，32轮非线性变换。采用非平衡Feistel结构，具有良好的安全性。",
            6: "SM7 - 中国国家密码管理局发布的流密码标准。128位密钥，具有高安全性和良好的随机性，适用于高速数据加密。",
            7: "ChaCha20 - Daniel Bernstein设计的流密码，基于Salsa20改进。256位密钥，高性能，抗时序攻击，被TLS 1.3采用。",
            8: "Blowfish - Bruce Schneier设计的分组密码，可变长度密钥(32-448位)。16轮Feistel网络，快速且安全，广泛用于文件加密。",
            9: "ZUC (祖冲之算法) - 中国自主设计的流密码算法，用于4G/5G通信加密。128位密钥，具有良好的随机性和抗攻击能力。"
        }
        return descriptions.get(self.n, f"{self.text} - 对称加密算法")


# 定义"非对称加密"牌子类 (替代原来的条牌)
class A(Tile):
    def __init__(self, n):
        super().__init__()
        self.kind = 'A'  # Asymmetric encryption
        self.n = n
        
        # 非对称加密算法映射
        asymmetric_algos = {
            1: ("RSA-1024", 1977, "1024位", "数字签名"),
            2: ("RSA-2048", 1977, "2048位", "HTTPS"),
            3: ("ECC-256", 1985, "256位", "移动设备"),
            4: ("DSA", 1991, "1024位", "数字签名"),
            5: ("DH", 1976, "2048位", "密钥交换"),
            6: ("Rabin", 1979, "可变", "加密系统"),
            7: ("SM2", 2010, "256位", "国产标准"),
            8: ("ElGamal", 1985, "2048位", "加密系统"),
            9: ("Kyber", 2020, "后量子", "密钥交换")
        }
        
        if 1 <= n <= 9:
            algo_info = asymmetric_algos[n]
            self.text = algo_info[0]
            self.year_invented = algo_info[1]
            self.key_length = algo_info[2]
            self.application = algo_info[3]
            self.security_level = n
            
            # 加载新的非对称加密算法图片
            try:
                image_name = {
                    1: "RSA.png",
                    2: "RSA.png",  # 使用同样的RSA图片
                    3: "ECC.png",
                    4: "DSA.png",
                    5: "DH.png",
                    6: "Rabin.png",
                    7: "SM2.png",
                    8: "ElGamal.png",
                    9: "Kyber.png"
                }[n]
                image_file = resource_path(os.path.join("麻将图片", "非对称", image_name))
                self.image = load_and_scale_image(image_file)
                self.rect = self.image.get_rect()
            except Exception as e:
                print(f"Error loading asymmetric algorithm image for {n}: {e}")
                # 创建一个默认的空白图片
                self.image = pygame.Surface((50, 54))
                self.image.fill((150, 150, 150))  # 灰色背景
                self.rect = self.image.get_rect()
        else:
            # 创建默认图片
            self.image = pygame.Surface((50, 54))
            self.image.fill((150, 150, 150))
            self.rect = self.image.get_rect()
            
        self.is_num = True
        if n >= 8:  # 8-9级为后量子算法
            self.is_post_quantum = True

    def get_detailed_description(self):
        """获取非对称加密算法的详细描述"""
        descriptions = {
            1: "RSA-1024 - Rivest-Shamir-Adleman算法，1024位密钥版本。基于大整数分解难题，曾广泛用于数字签名和密钥交换，现已不够安全。",
            2: "RSA-2048 - RSA算法的2048位密钥版本。提供更高安全性，广泛应用于HTTPS、邮件加密等。量子计算机威胁下仍需谨慎使用。",
            3: "ECC-256 - 椭圆曲线密码学，256位密钥。基于椭圆曲线离散对数问题，相比RSA提供相同安全性但密钥更短，适用于移动设备。",
            4: "DSA (数字签名算法) - 美国政府数字签名标准。基于离散对数问题，专门用于数字签名，不能用于加密，安全性依赖参数选择。",
            5: "DH (Diffie-Hellman) - 首个公开的密钥交换协议。允许双方在不安全信道上建立共享密钥，奠定了现代密码学基础。",
            6: "Rabin - 基于大整数分解难题的加密系统。可变长度密钥，提供高安全性，适用于加密系统。",
            7: "SM2 - 中国国家密码管理局制定的椭圆曲线公钥密码算法。256位密钥，支持加密、数字签名和密钥交换，具有自主知识产权。",
            8: "ElGamal - 基于离散对数问题的公钥密码系统。支持加密和数字签名，具有语义安全性，密文长度是明文的两倍。",
            9: "Kyber - NIST后量子密码标准中的密钥封装机制。基于格密码学的Learning With Errors问题，抗量子攻击，用于安全密钥交换。"
        }
        return descriptions.get(self.n, f"{self.text} - 非对称加密算法")


# 定义"哈希函数"牌子类 (替代原来的筒牌)
class H(Tile):
    def __init__(self, n):
        super().__init__()
        self.kind = 'H'  # Hash function
        self.n = n
        
        # 哈希函数映射
        hash_algos = {
            1: ("MD5", 1991, "128位", "文件校验"),
            2: ("SHA-1", 1995, "160位", "Git版本控制"),
            3: ("SHA-256", 2001, "256位", "比特币"),
            4: ("RIPEMD-160", 1996, "160位", "数字货币"),
            5: ("SHA-3", 2015, "可变", "NIST标准"),
            6: ("BLAKE3", 2020, "256位", "现代系统"),
            7: ("Scrypt", 2009, "可变", "密码存储"),
            8: ("SM3", 2010, "256位", "国产标准"),
            9: ("Yescrypt", 2013, "可变", "安全哈希")
        }
        
        if 1 <= n <= 9:
            algo_info = hash_algos[n]
            self.text = algo_info[0]
            self.year_invented = algo_info[1]
            self.key_length = algo_info[2]
            self.application = algo_info[3]
            self.security_level = n
            
            # 加载新的哈希函数图片
            try:
                image_name = {
                    1: "MD5.png",
                    2: "SHA-1.png",
                    3: "SHA-256.png",
                    4: "RIPEMD-160.png",
                    5: "SHA-3.png",
                    6: "BLAKE3.png",
                    7: "Scrypt.png",
                    8: "SM3.png",
                    9: "Yescrypt.png"
                }[n]
                image_file = resource_path(os.path.join("麻将图片", "哈希", image_name))
                self.image = load_and_scale_image(image_file)
                self.rect = self.image.get_rect()
            except Exception as e:
                print(f"Error loading hash algorithm image for {n}: {e}")
                # 创建一个默认的空白图片
                self.image = pygame.Surface((50, 54))
                self.image.fill((100, 100, 100))  # 深灰色背景
                self.rect = self.image.get_rect()
        else:
            # 创建默认图片
            self.image = pygame.Surface((50, 54))
            self.image.fill((100, 100, 100))
            self.rect = self.image.get_rect()
            
        self.is_num = True
        if n >= 9:  # 9级为后量子算法
            self.is_post_quantum = True

    def get_detailed_description(self):
        """获取哈希函数的详细描述"""
        descriptions = {
            1: "MD5 (消息摘要算法5) - 1991年设计，输出128位哈希值。曾广泛用于文件校验，但存在碰撞攻击漏洞，现已不推荐用于安全场景。",
            2: "SHA-1 (安全哈希算法1) - 1995年发布，160位输出。曾是互联网标准，但2017年谷歌实现碰撞攻击，现已被弃用。",
            3: "SHA-256 - SHA-2家族成员，256位输出。广泛应用于比特币、TLS等，具有良好的安全性和抗碰撞能力，是目前主流选择。",
            4: "RIPEMD-160 - 欧洲开发的哈希函数，160位输出。设计独特，抗差分攻击能力强，在某些数字货币中仍有应用。",
            5: "SHA-3 (Keccak) - 2015年NIST标准，基于海绵结构。设计理念与SHA-2完全不同，提供额外的安全保障，支持可变长度输出。",
            6: "BLAKE3 - 2020年发布的现代哈希函数。基于BLAKE2改进，极高性能，支持并行计算，适用于现代多核处理器。",
            7: "Scrypt - 2009年设计的密码派生函数。内存困难，抗ASIC攻击，广泛用于密码存储和某些加密货币的工作量证明。",
            8: "SM3 - 中国国家密码管理局制定的哈希函数标准。256位输出，结构类似SHA-256但有独特设计，具有自主知识产权。",
            9: "Yescrypt - 2013年设计的密码哈希函数。Scrypt的改进版本，更好的内存困难性和抗攻击能力，适用于高安全要求场景。"
        }
        return descriptions.get(self.n, f"{self.text} - 哈希函数")


# 定义"密码术语"牌子类 (替代原来的字牌)
class T(Tile):
    def __init__(self, n):
        super().__init__()
        self.kind = 'T'  # Terms
        self.n = n
        
        # 密码术语映射
        crypto_terms = {
            1: ("明文", "待加密的原始数据"),
            2: ("密文", "加密后的数据"),
            3: ("对称密钥", "对称加密的关键"),
            4: ("非对称密钥", "非对称加密的关键"),
            5: ("数字签名", "身份认证机制"),
            6: ("盐值", "哈希增强随机值"),
            7: ("随机数", "密码学安全基础"),
            8: ("量子计算机", "威胁经典密码的技术")
        }
        
        if 1 <= n <= 8:
            term_info = crypto_terms[n]
            self.text = term_info[0]
            self.application = term_info[1]
            
            # 量子计算机的特殊属性
            if n == 8:
                self.is_quantum = True
                self.security_level = 10  # 特殊等级
            
            # 加载新的密码术语图片
            try:
                image_name = {
                    1: "明文.png",
                    2: "密文.png",
                    3: "对称密钥.png",
                    4: "非对称密钥.png",
                    5: "数字签名.png",
                    6: "盐值.png",
                    7: "随机数.png",
                    8: "量子计算机.png"
                }[n]
                image_file = resource_path(os.path.join("麻将图片", "密码术语", image_name))
                self.image = load_and_scale_image(image_file)
                self.rect = self.image.get_rect()
            except Exception as e:
                print(f"Error loading crypto term image for {n}: {e}")
                # 创建一个默认的空白图片
                self.image = pygame.Surface((50, 54))
                self.image.fill((80, 80, 80))  # 暗灰色背景
                self.rect = self.image.get_rect()
        else:
            # 创建默认图片
            self.image = pygame.Surface((50, 54))
            self.image.fill((80, 80, 80))
            self.rect = self.image.get_rect()
            
        self.is_term = True
    
    def get_detailed_description(self):
        """获取密码术语的详细描述"""
        descriptions = {
            1: "明文 (Plaintext) - 未经加密的原始信息。在密码学中，明文是需要保护的敏感数据，通过各种加密算法转换为密文以确保安全传输和存储。",
            2: "密文 (Ciphertext) - 经过加密算法处理后的数据。密文对于没有解密密钥的人来说是不可读的，是信息安全的核心概念。",
            3: "对称密钥 (Symmetric Key) - 对称加密中用于加密和解密的相同密钥。密钥的安全分发是对称密码系统的主要挑战，但加解密速度快。",
            4: "非对称密钥 (Asymmetric Key) - 非对称加密中的密钥对，包括公钥和私钥。公钥可以公开，私钥必须保密，解决了密钥分发问题。",
            5: "数字签名 (Digital Signature) - 用于验证数据完整性和发送者身份的密码学机制。基于非对称密码学，提供不可否认性和身份认证。",
            6: "盐值 (Salt) - 在哈希计算中添加的随机数据。防止彩虹表攻击和相同密码产生相同哈希值，是密码存储的重要安全措施。",
            7: "随机数 (Random Number) - 密码学中的基础要素。用于生成密钥、初始化向量、盐值等。真随机性对密码系统安全至关重要。",
            8: "量子计算机 (Quantum Computer) - 利用量子力学原理进行计算的设备。Shor算法威胁RSA、ECC等经典公钥密码，推动后量子密码学发展。"
        }
        return descriptions.get(self.n, f"{self.text} - 密码学术语")

    def can_break(self, tile):
        """检查量子计算机是否可以破解指定算法"""
        if self.n == 8 and hasattr(self, 'is_quantum') and self.is_quantum:
            if tile.kind == 'A':  # 非对称加密
                # 可以破解RSA-1024, RSA-2048, ECC-256（编号1,2,3）
                return tile.n in [1, 2, 3]
        return False


class Table:  # 麻将桌类
    def __init__(self):
        self.__table = []

    def generate_tiles(self):
        # 生成对称加密牌 (9*4张)
        for i in range(4):
            for j in range(9):
                self.__table.append(S(j + 1))
        
        # 生成非对称加密牌 (9*4张)
        for i in range(4):
            for j in range(9):
                self.__table.append(A(j + 1))
        
        # 生成哈希函数牌 (9*4张)
        for i in range(4):
            for j in range(9):
                self.__table.append(H(j + 1))
        
        # 生成术语牌 (8*4张)，包括量子计算机
        for i in range(4):
            for j in range(8):
                self.__table.append(T(j + 1))
        
        # 注意：量子计算机现在是T(8)，已包含在术语牌中，总共138张牌
        
        random.shuffle(self.__table)

    def pop(self):
        # 从牌墙中弹出一张牌
        if self.remaining_tiles() > 0:
            return self.__table.pop()
        else:
            print("牌堆已空，无法继续抽牌！")
            return None

    def remaining_tiles(self):
        return len(self.__table)

    def draw(self):
        return self.__table.pop()

    @property  # 函数修饰符，将下面函数作为参数
    def table(self):
        return self.__table

    def get_tiles_by_kind(self, kind):
        return [tile for tile in self.__table if tile.kind == kind]

    def get_num_tiles(self):
        return [tile for tile in self.__table if tile.is_num]

    def get_crypto_tiles(self):
        """获取所有密码学算法牌"""
        return [tile for tile in self.__table if tile.kind in ['S', 'A', 'H']]

    def get_term_tiles(self):
        """获取所有术语牌"""
        return [tile for tile in self.__table if tile.is_term]

    def get_quantum_tiles(self):
        """获取所有量子牌"""
        return [tile for tile in self.__table if tile.is_quantum]


def main():


    # 比较两个实例是否相同
    if tile1 == tile2:
        print("两个实例相同")
    else:
        print("两个实例不同")


if __name__ == "__main__":
    main() 